//
// Created by LiuYou on 2021/10/19.
//

#include <iostream>
#include <unistd.h>
#include <cstring>


int main(int argc, char** argv) {



    // todo 笔记: 没有 \n , 这个想要打印的字符串就放到了输出缓冲区当中。
    //  所以如果没有加 \n , 将来 fork()的子进程是将父进程的输出缓冲区也拷贝一份的,
    //  如果缓冲区中有内容, 那么子进程也会打印一份。
    //  如果有 \n 的话, 在命令行上是行缓冲, 想要打印的字符串不会放到输出缓冲区中。
    printf( "fork();函数调用之前。进程[%d]。", getpid());
    // todo 笔记: 加上 \n , 在命令行上的输出是正确的, 只会输出一次。
    //  但是如果重定向的到文件的话, 加上 \n 还是会在文件中打印两次！
//    printf( "fork();函数调用之前。进程[%d]。\n", getpid());

    /*
     * 那为什么加上 \n , 是在命令行中输出一次, 而在文件中输出两次?
     * 命令行终端输出, 终端是标准的输出设备, 标准的输出设备是行缓冲模式, 所以, \n 会刷新缓冲区。
     * 而往文件中输出(即写一个文件), 文件是全缓冲模式, 所以这时 \n 已经不是刷新缓冲区了, 仅仅是换行的作用。
     * 也就是 printf( "fork();函数调用之前。进程[%d]。\n", getpid()); 中想要打印的字符串放到缓冲区当中了,
     * 还没来得及写到文件中的时候, 你马上 fork()了, 父子进程的各自缓冲区中各自有这个字符串, 所以才会出现两次。
     *
     *todo 笔记:
     * 因为子进程和父进程是一样的, 父进程已经执行过这条语句了。
     * 所以子进程创建出来后是直接在父进程的执行点。即 fork();语句这里,
     * 子进程不是创建出来后再和父进程那样从main函数开始再执行到 fork(); 函数这里,
     * 而是复制父进程, 直接和父进程一样。
     *
     */


//    std::cout << "fork();函数调用之前。" << "进程[" << getpid() << "]" << "\n";


    // todo 笔记: 在 fork();调用之前刷新所有成功打开的流, 将这些流中的缓冲区中的内容全部刷新。
    fflush( nullptr );
    pid_t pid = fork();
    if (pid < 0) {
        perror( "fork()" );
        fprintf( stderr, "fork(): %s", strerror(errno));
        exit( 1 );
    }
    if (pid == 0) {
        printf( "[%d]: 子进程工作中。\n", getpid());
    }
    if (pid > 0) {
//        sleep( 1 );
        printf( "[%d]: 父进程工作中。\n", getpid());
    }


    printf( "fork();函数调用之后。进程[%d]。\n", getpid());
//    std::cout << "fork();函数调用之后。" << "进程[" << getpid() << "]" << "\n";


    return 0;
}
